/**
 * 第2节
 * 知识点：
 * 1.学会词法分析；
 * 2.升级语法分析为LL算法，因此需要知道如何使用First和Follow集合。
 *
 * 本节采用的词法规则是比较精简的，比如不考虑Unicode。
 * Identifier: [a-zA-Z_][a-zA-Z0-9_]*
 *
 * EBNF规则：
 * prog = (functionDecl | functionCall)*
 * functionDecl: "function" Identifier "(" ")"  functionBody
 * functionBody : '{' functionCall* '}'
 * functionCall : Identifier '(' parameterList? ')'
 * parameterList : StringLiteral (',' StringLiteral)*
 *
 * 其他：
 * 系统调用以nl.开始
 * functionCall.name.startsWith("nl.")
 *
 * 运行：
 * cargo build
 *
 */

//#[macro_use]
//extern crate lazy_static;

mod mynl;

use std::env;
use std::io::Read;
use mynl::nast::Prog;
use mynl::nast::IAstNode;
use mynl::nast::IAstVisitor;
use mynl::nscanner::CharStream;
use mynl::nscanner::Tokenizer;
use mynl::nscanner::TokenKind;
use mynl::nparser::Parser;
use mynl::nsemantic::RefResolver;
use mynl::nintepretor::Intepretor;

/////////////////////////////////////////////////////////////////////////
// 主程序

fn compile_and_run(program:String) {
	//源代码
	println!("源代码:\n{}",program.clone());

	//词法分析
	println!("\n词法分析结果:");
	let mut tokenizer = Tokenizer::new(CharStream::new(program.clone()));
	while tokenizer.peek().kind != TokenKind::EOF {
        println!("{}", tokenizer.next());
	}
	tokenizer = Tokenizer::new(CharStream::new(program.clone())); //重置tokenizer,回到开头。

	//语法分析
	let mut prog: &mut Prog = &mut Parser::new(tokenizer).parse_prog();
	prog = prog;
	println!("\n语法分析后的AST，注意自定义函数的调用未被消解:");
	prog.dump(&String::from(""));

	//语义分析
	prog = RefResolver::visit_prog(prog);
	println!("\n语义分析后的AST，注意自定义函数的调用已被消解:");
	prog.dump(&String::from(""));

	//运行程序
	println!("\n运行当前的程序:");
	let ret_val = Intepretor::new().visit_prog(prog);
	if ret_val.is_none() {
		println!("程序返回值：None\n");
	} else{
		println!("程序返回值：{}\n", ret_val.unwrap());
	}
}

/////////////////////////////////////////////////////////////////////////
//程序入口
//处理命令行参数，从文件里读取源代码
fn main() {
	//运行示例
	// 要求命令行的第二个参数，一定是一个文件名。
    //let current_dir = env::current_dir();
    let args: Vec<String> = env::args().collect();
	if args.len() < 2 {
		println!("Usage: {} {}" , args[0], "FILENAME");
		return
	}

	// 读取源代码
    let mut file = std::fs::File::open(args[1].clone()).expect(&("Unable to open file ".to_owned() + &args[1]));
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

	compile_and_run(contents)
}
